/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.bemanager.rtmodule;

import com.inspur.edp.bef.bemanager.dependency.MavenDependency;
import com.inspur.edp.bef.bemanager.dependency.MavenDependencyConst;
import com.inspur.edp.bef.bemanager.dependency.ModifyPomUtil;
import com.inspur.edp.bef.bemanager.util.BefFileUtil;
import com.inspur.edp.caf.generator.compileunit.CompileUnitGenerator;
import com.inspur.edp.caf.generator.module.ModuleGenerator;
import com.inspur.edp.cef.rtgenerator.common.CefPreCompileManager;
import com.inspur.edp.cef.rtgenerator.common.CompileContext;
import com.inspur.edp.jittojava.context.service.CommonService;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.service.FileService;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.udt.rtgenerator.common.UdtCompileManager;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;

public class RuntimeModuleUtil {

  private MetadataService metadataService;
  private CommonService commonService;
  private FileService fileService;
  private final String shortRuntimeModuleName = "runtime";
//	private String projectPath = "E:\\projects\\Scm\\SD\\SalesOrder\\bo-salesorder-onlybe";
//	private String sourcePath = projectPath + "\\java\\Scm-SD-SalesOrder\\" +
//			"Scm-SD-SalesOrder-runtime\\src\\main\\java";
//	private String targetPath = projectPath + "\\java\\Scm-SD-SalesOrder\\" +
//			"Scm-SD-SalesOrder-runtime\\target\\classes";
//	private String serverPath = "E:\\gsp\\gsp_cloud\\gs-cloud-ds\\jstack";
//	//core的jar包全名
//	private String coreJarFileName = projectPath + "\\java\\Scm-SD-SalesOrder\\out" +
//			"\\artifacts\\com_inspur_gs_scm_sd_salesorder_core\\com.inspur.gs.scm.sd.salesorder.core.jar";
//	//api的jar包全名
//	private String apiJarFileName = projectPath + "\\java\\Scm-SD-SalesOrder\\out" +
//			"\\artifacts\\com_inspur_gs_scm_sd_salesorder_api\\com.inspur.gs.scm.sd.salesorder.api.jar";
//	private String jarFileName = "com.inspur.gs.scm.sd.salesorder.runtime";
//

  private RuntimeModuleUtil() {
  }

  public static RuntimeModuleUtil getInstance() {
    return new RuntimeModuleUtil();
  }

  /**
   * 运行时生成
   *
   * @param metadataProjPath
   * @return 新增runtime-module路径
   */
  public void rtGenerate(String metadataProjPath) {
    String rtModulePath = addRuntimeModule(metadataProjPath);
    // 触发运行时生成
    triggerRuntimeGenerate(metadataProjPath, rtModulePath);
  }

  private String addRuntimeModule(String metadataProjPath) {
    // 待实现
//		String projectPath = getCommonService().getProjectPath(metadataProjPath);
    String relativeJavaProjPath = getJavaProjPath(metadataProjPath);
    String javaProjPath = getAbsolutePath(relativeJavaProjPath);
    String projectPomPath = BefFileUtil.getPomFilePath(javaProjPath);
    Document doc = BefFileUtil.readDocument(projectPomPath);
    boolean isShortNameModule = isShortNameModule(doc.getRootElement());

    MavenDependency projectMavenInfo = readProjectMavenInfo(doc.getRootElement());
    String runtimeModuleArtifactId = getRtModuleArtifactName(projectMavenInfo.getArtifactId());
    String longModulePath = javaProjPath + "\\" + runtimeModuleArtifactId;
    String shortModulePath = javaProjPath + "\\" + shortRuntimeModuleName;
    // 1.已生成精简后runtime模块路径，无处理
    if (isShortNameModule && getFileService().isDirectoryExist(shortModulePath)) {
      return shortModulePath;
    }
    // 2.已生成普通runtime模块路径，若为精简模块名的工程，需重命名路径，修改工程pom文件
    if (getFileService().isDirectoryExist(longModulePath)) {
      if (isShortNameModule) {
        handleShortModulePath(longModulePath, shortModulePath, doc, projectPomPath);
        return shortModulePath;
      }
      return longModulePath;
    }
    // 3.未生成runtime模块
    // 添加runtime模块
    excecuteCommand(javaProjPath, projectMavenInfo, runtimeModuleArtifactId);
    // 安装依赖
    ArrayList<MavenDependency> dependencies = readRuntimeModuleDependency(projectMavenInfo);
    // TODO:jar包位置未确定，暂不安装api,core到本地仓库
    //ManageProjectDependencyUtil.getInstance().installPackage();
    // 添加引用
    ModifyPomUtil.getInstance().modifyPom(longModulePath,
        dependencies);
    // 处理模块名
    if (isShortNameModule) {
      // 此处doc需重新获取
      doc = BefFileUtil.readDocument(projectPomPath);
      handleShortModulePath(longModulePath, shortModulePath, doc, projectPomPath);
      return shortModulePath;
    }
    return longModulePath;
  }

  private void handleShortModulePath(String longModulePath, String shortModulePath, Document doc,
      String pomPath) {
    // 重命名runtime路径文件夹
    try {
      getFileService().renameDirectory(longModulePath, shortModulePath);
    } catch (IOException e) {
      throw new RuntimeException("重命名Runtime模块为精简形式失败:" + longModulePath);
    }

    // 修改工程pom中module名
    List<Element> moduleElements = doc.getRootElement().element(MavenDependencyConst.modules)
        .elements();
    for (Element ele : moduleElements) {
      if (ele.getText().contains("runtime")) {
        ele.setText(shortRuntimeModuleName);
        BefFileUtil.saveDocument(doc, new File(pomPath));
        return;
      }
      continue;
    }
    throw new RuntimeException("在工程pom文件重命名Runtime模块失败：" + pomPath);
  }

  private boolean isShortNameModule(Element projectElement) {
    Element modulesElement = projectElement.element(MavenDependencyConst.modules);
    List<Element> moduleElements = modulesElement.elements();
    boolean isShortNameModule = false;
    for (Element ele : moduleElements) {
      if (ele.getText().equals("api")) {
        return true;
      }
      continue;
    }
    return isShortNameModule;
  }

  private void triggerRuntimeGenerate(String metadataProjPath, String rtModulePath) {
    String absoluteProjPath = getAbsolutePath(metadataProjPath);
    String rtSourcePath = rtModulePath + "\\src\\main\\java";
    String rtTargetPath = rtModulePath + "\\target";
    if (!getFileService().isDirectoryExist(rtTargetPath)) {
      getFileService().createDirectory(rtTargetPath);
    }

    if (getFileService().isDirectoryExist(rtSourcePath)) {
      try {
        getFileService().deleteAllFilesUnderDirectory(rtSourcePath);
      } catch (Exception e) {
        //throw new RuntimeException("Runtime代码清理失败",e);
        //如果删除失败，重新生成即可。不影响主流程，不需要因为删除失败终止程序
      }
    }

    List<String> projectJarPaths = null;

    projectJarPaths = getCommonService().getJarPath(absoluteProjPath);

    String apiJarFileFullName = getApiJarFullName(absoluteProjPath, projectJarPaths);
    String coreJarFileFullName = getCoreJarFullName(absoluteProjPath, projectJarPaths);
    String compJarFileFullName = getCompJarFullName(absoluteProjPath, projectJarPaths);
    String rtJarFileName = getRtJarFileName(apiJarFileFullName);
    String serverPath = getServerPath();

    String str = getGenTempFolderPath(getJavaProjPath(metadataProjPath));
    String curDateString = getCurrentDateString();
    tryDeleteOldFiles(str);
    apiJarFileFullName = copyApiJarFile(apiJarFileFullName, str, curDateString);
    coreJarFileFullName = copyCoreJarFile(coreJarFileFullName, str, curDateString);
    if (!"".equals(compJarFileFullName)) {
      compJarFileFullName = copyCoreJarFile(compJarFileFullName, str, curDateString);
    }
    triggerRuntimeGenerate(
        metadataProjPath,
        rtSourcePath,
        rtTargetPath,
        rtJarFileName,
        serverPath,
        coreJarFileFullName,
        apiJarFileFullName,
        compJarFileFullName);
  }

  private void tryDeleteOldFiles(String path) {
    File dir = new File(path);
    if (dir.exists() == false) {
      dir.mkdir();
    }
    if (dir.listFiles() == null) {
      return;
    }
    for (File file : dir.listFiles()) {
      if (file.isDirectory() == false) {
        continue;
      }
      for (File file1 : file.listFiles()) {
        if (file1.isDirectory()) {
          continue;
        }
        try {
          file1.delete();
        } catch (Exception e) {
        }
      }
      try {
        file.delete();
      } catch (Exception e) {
      }
    }
  }

  private String copyApiJarFile(String apiJarFileFullName, String str, String curDateString) {
    File file = new File(apiJarFileFullName);
    Path targetFile = Paths.get(str + "\\" + curDateString + "\\" + file.getName());
    try {
      File file1 = new File(str + "\\" + curDateString + "\\" + file.getName());
      File dir = new File(str + "\\" + curDateString);
      if (dir.exists() == false) {
        dir.mkdir();
      }
      if (file1.exists() == false) {
        file1.createNewFile();
      }
      Files.copy(file.toPath(), targetFile, StandardCopyOption.REPLACE_EXISTING);
    } catch (IOException e) {
      throw new RuntimeException("复制文件时出错，错误信息：" + e.getMessage(), e);
    }
    return new File(str + "\\" + curDateString + "\\" + file.getName()).getAbsolutePath();
  }

  private String copyCoreJarFile(String coreJarFileFullName, String str, String curDateString) {
    File file = new File(coreJarFileFullName);
    Path targetFile = Paths.get(str + "\\" + curDateString + "\\" + file.getName());
    try {
      File file1 = new File(str + "\\" + curDateString + "\\" + file.getName());
      if (file1.exists() == false) {
        file1.createNewFile();
      }
      Files.copy(file.toPath(), targetFile, StandardCopyOption.REPLACE_EXISTING);
    } catch (IOException e) {
      throw new RuntimeException(
          "复制文件时出错，文件路径为：" + file.toPath() + "---" + targetFile + " ,错误信息：" + e.getMessage(), e);
    }
    return new File(str + "\\" + curDateString + "\\" + file.getName()).getAbsolutePath();
  }


  private String getGenTempFolderPath(String javaProjPath) {
    String outPath = getAbsolutePath(javaProjPath) + "\\out";
    File outFile = new File(outPath);
    if (outFile.exists() == false) {
      outFile.mkdir();
    }

    String tempPath = outPath + "\\genTemp";
    File file = new File(tempPath);
    if (file.exists() == false) {
      file.mkdir();
    }
    return tempPath;
  }

  private String getCurrentDateString() {
    Date date = new Date();
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(date.getYear()).append(date.getMonth()).append(date.getDay())
        .append(date.getHours()).append(date.getMinutes()).append(date.getSeconds());
    return stringBuilder.toString();
  }

  public void triggerRuntimeGenerate(String metadataProjPath, String rtSoucePath,
      String rtTargetPath,
      String jarFileName,
      String serverPath, String coreJarFileName, String apiJarFileName, String compJarFileName) {
    System.out.println("开始生成runtime代码");
    CompileContext context = createCompileContext(metadataProjPath, coreJarFileName, apiJarFileName,
        rtSoucePath,
        serverPath, compJarFileName);
    List<GspMetadata> metadataList = getProjGspMetadataList(metadataProjPath);
    for (GspMetadata meta : metadataList) {
      triggerMetadataRtGenerator(meta, context);
    }
    context.getBaseGenerator().initialize();
    context.getBaseGenerator().generate();

    ArrayList<String> jarPaths = new ArrayList<String>();
    jarPaths.add(getAbsolutePath(metadataProjPath));
    jarPaths.add(serverPath);
    System.out.println("runtime代码生成完成");
//		context.getBaseGenerator().build(rtSoucePath, rtTargetPath, jarPaths, jarFileName,
//				rtTargetPath);
  }

  //region 添加模块
  private String getRtModuleArtifactName(String projectArtifactName) {
    return projectArtifactName + "-runtime";
  }

  private ArrayList<MavenDependency> readRuntimeModuleDependency(MavenDependency projectMavenInfo) {
    ArrayList<MavenDependency> dependencies = new ArrayList<>();
    String groupId = projectMavenInfo.getGroupId();
    String version = projectMavenInfo.getVersion();
    String apiArtifactId = projectMavenInfo.getArtifactId() + "-api";
    String coreArtifactId = projectMavenInfo.getArtifactId() + "-core";
    dependencies.add(new MavenDependency(groupId, apiArtifactId, version));
    dependencies.add(new MavenDependency(groupId, coreArtifactId, version));
    return dependencies;
  }

  private void excecuteCommand(String projectPath, MavenDependency info,
      String runtimeModuleArtifactId) {
    String command = String.format("cmd /c cd %s", projectPath);
    String groupId = info.getGroupId();
    String addModuleCommand = String.format("mvn archetype:generate -DgroupId=%1$s " +
            " -DartifactId=%2$s -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false",
        groupId, runtimeModuleArtifactId);
    command = command.concat(" && " + addModuleCommand);
    Process process = null;
    BefFileUtil.excecuteCommand(process, command, "添加bef运行时模块");
  }

  private MavenDependency readProjectMavenInfo(Element root) {
    String groupId = BefFileUtil.getTagValue(root, MavenDependencyConst.groupId);
    String artifactId = BefFileUtil.getTagValue(root, MavenDependencyConst.artifactId);
    String version = BefFileUtil.getTagValue(root, MavenDependencyConst.version);
    return new MavenDependency(groupId, artifactId, version);
  }
  //endregion

  // region 路径拼写

  private String getJavaProjPath(String projPath) {
    return BefFileUtil.getJavaProjPath(projPath);
  }

  private String getServerPath() {
    return BefFileUtil.getServerPath();
  }

  private String getApiJarFullName(String projPath, List<String> projectJarPaths) {
    String apiJarFileFullName = "";
    for (String path : projectJarPaths) {
      if (path.contains("out\\genTemp") || path.contains("out/genTemp")) {
        continue;
      }
      if (path.endsWith("-api-0.1.0-SNAPSHOT.jar") || path.endsWith("api.jar") || path
          .contains("-api-")) {
        apiJarFileFullName = projPath + "\\" + path;
        break;
      }
    }
    if (apiJarFileFullName.isEmpty()) {
      throw new RuntimeException("无法找到api的jar包路径");
    }
    return apiJarFileFullName;
  }

  private String getCompJarFullName(String projPath, List<String> projectJarPaths) {
    String compJarFileFullName = "";
    for (String path : projectJarPaths) {
      if (path.contains("out\\genTemp") || path.contains("out/genTemp")) {
        continue;
      }
      if (path.endsWith("-comp-0.1.0-SNAPSHOT.jar") || path.endsWith("comp.jar") || path
          .contains("-comp-")) {
        compJarFileFullName = projPath + "\\" + path;
        break;
      }
    }
//		if (compJarFileFullName.isEmpty()) {
//			throw new RuntimeException("无法找到comp的jar包路径");
//		}
    return compJarFileFullName;
  }

  private String getCoreJarFullName(String projPath, List<String> projectJarPaths) {
    String coreJarFileFullName = "";
    for (String path : projectJarPaths) {
      if (path.contains("out\\genTemp") || path.contains("out/genTemp")) {
        continue;
      }
      if (path.endsWith("-core-0.1.0-SNAPSHOT.jar") || path.endsWith("core.jar") || path
          .contains("-core-")) {
        coreJarFileFullName = projPath + "\\" + path;
        break;
      }
    }
    if (coreJarFileFullName.isEmpty()) {
      throw new RuntimeException("无法找到core的jar包路径");
    }
    return coreJarFileFullName;
  }

  private String getRtJarFileName(String apiJarFileFullName) {
    String[] apiJarFileNameList = apiJarFileFullName.split("\\\\");
    String apiJarFileName = apiJarFileNameList[apiJarFileNameList.length - 1];
    String rtJarFileName = apiJarFileName.replace(".api", ".runtime");
    rtJarFileName = rtJarFileName.replace("-api", "-runtime");
    return rtJarFileName;
  }

  private List<String> getMockJarPath() {
    ArrayList<String> list = new ArrayList<>();
    list.add(
        "java\\Scm-SD-SalesOrder\\Scm-SD-SalesOrder-api\\target\\Scm-SD-SalesOrder-api-0.1.0-SNAPSHOT.jar");
    list.add(
        "java\\Scm-SD-SalesOrder\\Scm-SD-SalesOrder-core\\target\\Scm-SD-SalesOrder-core-0.1.0-SNAPSHOT.jar");
    return list;
  }
  // endregion

  //region 运行时生成


  private CompileContext createCompileContext(String metadataProjPath, String coreJarFileName,
      String apiJarFileName, String rtSourcePath, String serverPath,
      String compJarFilelName) {
    CompileContext context = new CompileContext();
    context.setProjPath(metadataProjPath);
    context.setBaseGenerator(createRuntimeModuleGenerator());
    context.setCoreJarFileName(coreJarFileName);
    context.setApiJarFileName(apiJarFileName);
    context.setGeneratedPath(rtSourcePath);
    context.setServerPath(serverPath);
    context.setCompJarFileName(compJarFilelName);
    return context;
  }

  private ModuleGenerator createRuntimeModuleGenerator() {
    return new ModuleGenerator() {
      @Override
      protected ArrayList<CompileUnitGenerator> getCompileUnitGenrators() {
        return null;
      }
    };
  }

  private List<GspMetadata> getProjGspMetadataList(String metaProjPath) {
    return getMetadataService().getMetadataList(metaProjPath);
  }

  private CommonService getCommonService() {
    if (commonService == null) {
      commonService = BefFileUtil.getService(CommonService.class);
    }
    return commonService;
  }

  private MetadataService getMetadataService() {
    if (metadataService == null) {
      metadataService = BefFileUtil.getService(MetadataService.class);
    }
    return metadataService;
  }

  private FileService getFileService() {
    if (fileService == null) {
      fileService = BefFileUtil.getService(FileService.class);
    }
    return fileService;
  }

  private void triggerMetadataRtGenerator(GspMetadata metadata, CompileContext context) {
    CefPreCompileManager compileManager = getRtCompileManager(metadata);
    if (compileManager == null) {
      return;
    }
    compileManager.build(context);
  }

  private CefPreCompileManager getRtCompileManager(GspMetadata metadata) {
    switch (metadata.getHeader().getType()) {
      // todo:依赖
//			case "GSPBusinessEntity":
//				return new BefCompileManager(loadMetadata(metadata));
//			case "GSPViewModel":
//				return new BffCompileManager(loadMetadata(metadata));
      case "UnifiedDataType":
        return new UdtCompileManager(loadMetadata(metadata));
      default:
//				throw new RuntimeException("不支持的元数据类型" + type);
        return null;
    }
  }

  private GspMetadata loadMetadata(GspMetadata item) {
    //todo:元数据按relativePath加载存在问题
    return getMetadataService().loadMetadata(item.getHeader().getFileName(),
        item.getRelativePath());
  }

  private String getAbsolutePath(String relativePath) {
    String devPath = getFileService().getDevRootPath();
    return Paths.get(devPath).resolve(relativePath).toString();
  }
  //endregion
}
